using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public static class Utils
{
  public static T SafeGet<T>(this T[,] arr, Vector2Int pos, T defaultVal = default(T)) {
    if (arr == null)
    {
      return defaultVal;
    }
    var size0 = arr.GetLength(0);
    var size1 = arr.GetLength(1);
    if (pos.x > -1 && pos.y > -1 &&
        pos.x < size0 && pos.y < size1)
    {
      return arr[pos.x, pos.y];
    }
    return defaultVal;
  }

  public static TVal SafeGet<TKey, TVal>(this Dictionary<TKey, TVal> dict, TKey key, TVal defaultVal = default(TVal)) {
    if (dict == null || !dict.ContainsKey(key))
    {
      return defaultVal;
    }
    return dict[key];
  }

  public static int SafeCount<T>(this IList<T> list) {
    if (list == null)
    {
      return 0;
    }
    return list.Count;
  }

  public static bool TrySet<T>(this T[,] arr, Vector2Int pos, T val) {
    if (arr == null)
    {
      return false;
    }
    var size0 = arr.GetLength(0);
    var size1 = arr.GetLength(1);
    if (pos.x > -1 && pos.y > -1 &&
        pos.x < size0 && pos.y < size1)
    {
      arr[pos.x, pos.y] = val;
      return true;
    }
    return false;
  }

  public static IEnumerable<Vector2Int> AllPosition<T>(this T[,] arr) {
    if (arr == null)
    {
      yield break;
    }
    var size0 = arr.GetLength(0);
    var size1 = arr.GetLength(1);
    for (int x = 0; x < size0; x++)
    {
      for (int y = 0; y < size1; y++)
      {
        yield return new Vector2Int(x, y);
      }
    }
  }

  public static Vector2Int SafeSize<T>(this T[,] arr) {
    if (arr == null)
    {
      return Vector2Int.zero;
    }
    return new Vector2Int(arr.GetLength(0), arr.GetLength(1));
  }

  public static Vector3Int ToV3I(this Vector2Int v2i) {
    return new Vector3Int(v2i.x, v2i.y);
  }

  public static bool SafeContains<T>(this T[,] arr, Vector2Int elementPos) {
    if (arr == null)
    {
      return false;
    }
    return elementPos.x > -1 && elementPos.y > -1 &&
           elementPos.x < arr.GetLength(0) && elementPos.y < arr.GetLength(1);
  }

  public static void SetAlpha(this SpriteRenderer sr, float alpha) {
    var color = sr.color;
    color.a = alpha;
    sr.color = color;
  }

  public static bool IsNullOrComponentNull(this object obj) {
    if (obj == null)
    {
      return true;
    }
    if (obj is Component component)
    {
      return component == null;
    }
    return false;
  }

  public static bool MouseClick(out Vector2 pos, int mouseButton = 0) {
    bool res = Input.GetMouseButtonDown(mouseButton);
    pos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
    return res;
  }

  public static void DestroyAllChildren(this Transform transform) {
    if (transform == null)
    {
      return;
    }
    var childCount = transform.childCount;
    for (int i = 0; i < childCount; i++)
    {
      GameObject.Destroy(transform.GetChild(i).gameObject);
    }
  }

  public static void DestroyAllChildrenImmediate(this Transform transform) {
    if (transform == null)
    {
      return;
    }
    while (transform.childCount > 0)
    {
      GameObject.DestroyImmediate(transform.GetChild(0).gameObject);
    }
  }

  public static Rect GetScreenRect(this RectTransform rt) {
    var rect = rt.rect;
    rect.center = rt.position;
    return rect;
  }

  public static Rect RectFromMinMax(Vector2 a, Vector2 b) {
    Rect rect = new Rect();
    rect.xMin = Mathf.Min(a.x, b.x);
    rect.xMax = Mathf.Max(a.x, b.x);
    rect.yMin = Mathf.Min(a.y, b.y);
    rect.yMax = Mathf.Max(a.y, b.y);
    return rect;
  }
}

public struct Dirty
{
  private bool m_dirty;

  public void Set() {
    m_dirty = true;
  }

  public bool Pop() {
    var tmp = m_dirty;
    m_dirty = false;
    return tmp;
  }
}